Ga naar hoofdinhoud

Properties en data doorgeven aan componenten

Hoe gebruik je defineProps en defineModel in Vue 3 met TypeScript?

Vue 3 introduceert krachtige composable functies zoals defineProps en defineModel, waarmee je componenten eenvoudig kunt structureren en tweerichtingsbindingen kunt beheren. In deze les leer je hoe je deze functies gebruikt om properties door te geven en data te binden in Vue 3, met TypeScript en script setup. We maken samen een custom Input- en Button-component.

Wat zijn defineProps en defineModel?

defineProps

defineProps is een composable functie in Vue 3 waarmee je props kunt definiëren in een script setup-blok. Dit maakt het eenvoudiger om component-eigenschappen te beheren, inclusief hun types en standaardwaarden.

defineModel

Vanaf Vue 3.3 is defineModel geïntroduceerd. Het vereenvoudigt het gebruik van v-model door expliciete ondersteuning voor tweerichtingsbinding. Met defineModel kun je een waarde rechtstreeks binden aan een prop zonder dat je handmatig een update:modelValue-event hoeft te emitten.

Laten we nu naar enkele praktische voorbeelden kijken.

Voorbeeld 1: Een custom Input-component

Probleemstelling

Stel, je wilt een herbruikbare input maken met een label. Deze moet een v-model ondersteunen zodat de oudercomponent eenvoudig de waarde kan beheren.

Oplossing met defineProps

Hier is de basisversie van een custom Input-component:

<script setup lang="ts">
import { defineProps } from 'vue';

const { label, inputType = 'text', value } = defineProps<{
label: string;
inputType?: string;
value: string;
}>();

const emit = defineEmits<{
(event: 'update:value', newValue: string): void;
}>();

const handleInput = (event: Event) => {
const target = event.target as HTMLInputElement;
emit('update:value', target.value);
};
</script>

<template>
<div>
<label>{{ label }}</label>
<input :type="inputType" :value="value" @input="handleInput" />
</div>
</template>

Uitleg

  1. Props definiëren: Met defineProps accepteren we label, inputType (met een standaardwaarde van text), en value.
  2. Events definiëren: Met defineEmits definiëren we een update:value-event.
  3. Input handler: Wanneer de gebruiker typt, emiten we de nieuwe waarde naar de oudercomponent.

Gebruik in de oudercomponent

<script setup lang="ts">
import CustomInput from './CustomInput.vue';
import { ref } from 'vue';

const inputValue = ref('');
</script>

<template>
<div>
<CustomInput label="Name" v-model:value="inputValue" />
<p>Input Value: {{ inputValue }}</p>
</div>
</template>

Wat gebeurt hier?

  • v-model:value bindt de waarde van inputValue aan de value-prop van het kindcomponent.
  • Het update:value-event zorgt ervoor dat wijzigingen teruggestuurd worden naar de oudercomponent.

Voorbeeld 2: Eenvoudiger met defineModel

Waarom defineModel gebruiken?

defineModel maakt de implementatie van v-model eenvoudiger en explicieter. Hiermee kun je direct een prop met bijbehorende events beheren zonder handmatig update:modelValue te configureren.

Hier is de aangepaste versie van het Input-component met defineModel:

<script setup lang="ts">
const { label, inputType = 'text' } = defineProps<{
label: string;
inputType?: string;
}>();

const modelValue = defineModel<string>();

const handleInput = (event: Event) => {
const target = event.target as HTMLInputElement;
modelValue.value = target.value;
};
</script>

<template>
<div>
<label>{{ label }}</label>
<input :type="inputType" :value="modelValue" @input="handleInput" />
</div>
</template>

Uitleg

  1. defineModel: We gebruiken defineModel om een prop genaamd modelValue te definiëren.
  2. Tweerichtingsbinding: Wijzigingen aan modelValue worden automatisch gesynchroniseerd met de oudercomponent.

Gebruik in de oudercomponent

<script setup lang="ts">
import CustomInput from './CustomInput.vue';
import { ref } from 'vue';

const inputValue = ref('');
</script>

<template>
<div>
<CustomInput label="Name" v-model="inputValue" />
<p>Input Value: {{ inputValue }}</p>
</div>
</template>

Met defineModel hoef je geen expliciete update:modelValue-events meer te definiëren.

Verschil tussen :type en type

Wanneer je een attribuut aan een HTML-element doorgeeft, is het belangrijk om het onderscheid tussen :type en type te begrijpen:

  1. :type: Dit gebruik je in Vue om dynamisch een waarde door te geven aan het attribuut. Het attribuut krijgt de waarde van een JavaScript-expressie.
  2. type: Dit is een statische stringwaarde die rechtstreeks aan het HTML-element wordt doorgegeven.

Voorbeeld

<template>
<!-- Dynamische waarde -->
<input :type="inputType" />

<!-- Statische waarde -->
<input type="text" />
</template>

In het bovenstaande voorbeeld wordt :type="inputType" afhankelijk van de waarde van inputType gewijzigd, terwijl type="text" altijd text zal zijn.

Praktische toepassing in een component

Als je bijvoorbeeld een inputtype dynamisch wilt bepalen:

<script setup lang="ts">
const { inputType = 'text' } = defineProps<{ inputType?: string }>();
</script>

<template>
<input :type="inputType" />
</template>

De oudercomponent kan nu het type dynamisch bepalen:

<CustomInput :inputType="'password'" />

Een functie doorgeven aan een component

Je kunt ook functies doorgeven als props aan een component. Dit is handig wanneer je een kindcomponent een specifieke actie wilt laten uitvoeren.

Voorbeeld

Hier is een Button-component die een functie accepteert:

<script setup lang="ts">
const { label, onClick } = defineProps<{
label: string;
onClick: () => void;
}>();
</script>

<template>
<button @click="onClick">{{ label }}</button>
</template>

Gebruik in de oudercomponent

<script setup lang="ts">
import CustomButton from './CustomButton.vue';

const handleClick = () => {
alert('Button clicked!');
};
</script>

<template>
<CustomButton label="Click Me" :onClick="handleClick" />
</template>

In dit voorbeeld wordt de handleClick-functie doorgegeven aan de Button-component via de prop onClick. Wanneer op de knop wordt geklikt, voert de knop de functie uit.

Conclusie

In deze les heb je geleerd hoe je defineProps en defineModel kunt gebruiken in Vue 3:

  1. defineProps stelt je in staat om componentprops typeveilig en eenvoudig te definiëren.
  2. defineModel (vanaf Vue 3.3) vereenvoudigt tweerichtingsbindingen met v-model.
  3. Je hebt het verschil tussen :type en type geleerd en hoe je een functie kunt doorgeven aan een component.

Met deze kennis kun je herbruikbare en goed gestructureerde componenten maken die eenvoudig in grotere projecten kunnen worden toegepast. Ga aan de slag en probeer je eigen custom componenten te maken! 🚀